/**
 * Created with  SublimeText
 * @Author:      Lyle
 * @DateTime:    2017-07-25 15:01:47  Refactoring xmltojson and delete JQ
 * @Description: 
 */

import xmlToJSON from '../xmltojson/xmltojson'

var NAME_SEPARATOR = '__',
    _xmlns_preference_prefix = 'xmpp:preference:',
    _retry_times = 1,
    MAX_RETRY_TIMES = 3,
    _disconnected = false;


var MiniIM = (function(self, Strophe) {

    var _connection = null,

        _service = null,

        _domain = null,

        _sessionId = null,

        _loginName = null,

        _loginPassword = null,

        _unloadFunction = null,

        _addNamespace = function(name, value) {
            Strophe.addNamespace(name, value);
        },

        _addNamespaces = function() {
            _addNamespace('PRIVATE', 'jabber:iq:private');
            _addNamespace('DELAY', 'jabber:x:delay');
            _addNamespace('ARCHIVE', 'urn:xmpp:archive');
            _addNamespace('TIME', 'urn:xmpp:time');
        },

        _registerEventHandlers = function() {
            //self.addHandler(self.Handler.Version, Strophe.NS.VERSION, 'iq');
            self.addHandler(self.Handler.Jabber.Presence, null, 'presence');
            self.addHandler(self.Handler.Jabber.Message, null, 'message');
            self.addHandler(self.Handler.Jabber.Bookmarks, Strophe.NS.PRIVATE, 'iq');
            self.addHandler(self.Handler.Jabber.Archive, Strophe.NS.ARCHIVE, 'iq', 'result');
            //self.addHandler(self.Handler.Jabber.Time, Strophe.NS.TIME, 'iq', 'result');
            //self.addHandler(self.Handler.StreamError, null, 'stream:error');
        },

        _getEscapedJidFromJid = function(jid) {
            var node = Strophe.getNodeFromJid(jid),
                domain = Strophe.getDomainFromJid(jid);
            return node ? Strophe.escapeNode(node) + '@' + domain : domain;
        };

    self.TYPE = {
        ROOM: 1, // public chat room
        PRIVATE: 2, // personal private chat
        GROUP: 3 // group user created
    };

    self.init = function(service, domain, sessionId, options) {
        _service = service;
        _domain = domain;
        _sessionId = sessionId;
        _addNamespaces();

        _connection = new Strophe.Connection(_service, options);
        _connection.rawInput = self.rawInput.bind(self);
        _connection.rawOutput = self.rawOutput.bind(self);

        window.onbeforeunload = self.onWindowUnload;

        self.log = function(str) {
            try { // prevent erroring
                if (typeof window.console !== undefined && typeof window.console.log !== undefined) {
                    console.log(str);
                }
            } catch (e) {
                //console.error(e);
            }
        };
        self.log('[Init] Debugging enabled');
    };

    self.connect = function(jidOrHost, password, nick) {
        _loginName = jidOrHost;
        _loginPassword = password;
        // Reset before every connection attempt to make sure reconnections work after authfail, alltabsclosed, ...
        _connection.reset();
        _registerEventHandlers();
        _disconnected = false;

        if (jidOrHost && password) {
            // authentication
            _connection.connect(_getEscapedJidFromJid(jidOrHost) + '/mobilesite-' + Math.random().toString(36).substr(2), password, MiniIM.Handler.Strophe.Connect);
        } else if (jidOrHost && nick) {
            // anonymous connect
            _connection.connect(_getEscapedJidFromJid(jidOrHost) + '/mobilesite-' + Math.random().toString(36).substr(2), null, MiniIM.Handler.Strophe.Connect);
        } else {
            alert('Please provide connect username and password to login');
        }
    };

    self.disconnect = function() {
        _disconnected = true;
        if (_connection.connected) {
            _connection.disconnect();
        }
    };

    self.getConnection = function() {
        return _connection;
    };

    self.getService = function() {
        return _service;
    };

    self.isConnected = function() {
        return _connection.connected;
    }

    self.getDomain = function() {
        return _domain;
    };

    self.getOwnJid = function() {
        return _connection.jid;
    };

    self.getSessionId = function() {
        return _sessionId;
    };

    self.getLoginName = function() {
        return _loginName;
    };

    self.getLoginPassword = function() {
        return _loginPassword;
    };

    self.addHandler = function(handler, ns, name, type, id, from, options) {
        return _connection.addHandler(handler, ns, name, type, id, from, options);
    };

    self.onWindowUnload = function() {
        // Enable synchronous requests because Safari doesn't send asynchronous requests within unbeforeunload events.
        // Only works properly when following patch is applied to strophejs: https://github.com/metajack/strophejs/issues/16/#issuecomment-600266
        _connection.sync = true;
        self.disconnect();
        _connection.flush();
    };

    self.rawInput = function(data) {
        this.log('RECV: ' + data);
    };

    self.rawOutput = function(data) {
        this.log('SENT: ' + data);
    };

    return self;

}(MiniIM || {}, StropheLib.Strophe));


MiniIM.Action = (function(self, Strophe) {

    self.messageMirror = function(bool) {
        var xml;
        if (bool) {
            xml = StropheLib.$iq({ type: 'set', from: MiniIM.getOwnJid(), id: 'enable1' }).c('enable', { xmlns: 'urn:xmpp:carbons:2' }).tree();
        } else {
            xml = StropheLib.$iq({ type: 'set', from: MiniIM.getOwnJid(), id: 'disable1' }).c('disable', { xmlns: 'urn:xmpp:carbons:2' }).tree();
        }
        MiniIM.getConnection().send(xml);
    };

    self.joinRoom = function(roomName, password) {
        var ownerJid = MiniIM.getOwnJid();
        var roomJid = roomName + '@conference.' + Strophe.getDomainFromJid(ownerJid);
        MiniIM.getConnection().send(
            StropheLib.$iq({ type: 'get', from: MiniIM.getOwnJid(), to: roomJid, id: 'disco3' }).c('query', { xmlns: Strophe.NS.DISCO_INFO }).tree());
        MiniIM.getConnection().muc.join(roomJid, MiniIM.Util.getRealName(ownerJid), null, null, password);
    };

    self.leaveRoom = function(roomName) {
        var ownerJid = MiniIM.getOwnJid();
        var roomJid = roomName + '@conference.' + Strophe.getDomainFromJid(ownerJid);
        MiniIM.getConnection().muc.leave(roomJid, MiniIM.Util.getRealName(ownerJid), function() {});
    };

    self.sendMessage = function(receiver, message, type, params) {
        type = type || 'chat';

        if (message === '' || receiver == undefined || receiver === '') {
            return false;
        }

        var msgid = MiniIM.getConnection().getUniqueId();
        var id = params['id'] || 'noset';
        if (type === 'chat') {
            var msg = StropheLib.$msg({ to: MiniIM.Util.toJid(receiver), from: MiniIM.getOwnJid(), type: 'chat', id: msgid, flag: id }).
            c('body', { xmlns: Strophe.NS.CLIENT }).t(message);
            if (params['senderId']) {
                msg.up().c("senderid").t(params['senderId']);
            }
            if (params['receiverId']) {
                msg.up().c("receiverid").t(params['receiverId']);
            }
            if (params['font']) {
                msg.up().c("x", { xmlns: "jabber:x:event" }).c("font", params['font']);
            }
            if (params['image'] && params['url']) {
                if (params['font']) {
                    msg.up().c('image');
                } else {
                    msg.up().c("x", { xmlns: "jabber:x:event" }).c('image');
                }
                msg.c('link').t(params['url']);
                if (params['lifetime']) {
                    msg.up().c('lifetime').t(params['lifetime']);
                }
                if (params['ix'] && params['iy']) {
                    msg.up().c('ix').t(params['ix']);
                    msg.up().c('iy').t(params['iy']);
                }
                msg.up().up().up().c('ext-info', { xmlns: "chat:xmpp:extend" }).c('type').t('image');
            }

            MiniIM.getConnection().send(msg);
        } else if (type === 'groupchat') {
            var roomJid = receiver + '@conference.' + Strophe.getDomainFromJid(MiniIM.getOwnJid());
            var msg = StropheLib.$msg({ to: roomJid, from: MiniIM.getOwnJid(), type: 'groupchat', id: MiniIM.getConnection().getUniqueId(), flag: id }).
            c("body", { xmlns: Strophe.NS.CLIENT }).t(message);
            if (params['font']) {
                msg.up().c("x", { xmlns: "jabber:x:event" }).c("font", params['font']);
            }
            if (params['image'] && params['url']) {
                if (params['font']) {
                    msg.up().c('image');
                } else {
                    msg.up().c("x", { xmlns: "jabber:x:event" }).c('image');
                }
                msg.c('link').t(params['url']);
                if (params['lifetime']) {
                    msg.up().c('lifetime').t(params['lifetime']);
                }
                if (params['ix'] && params['iy']) {
                    msg.up().c('ix').t(params['ix']);
                    msg.up().c('iy').t(params['iy']);
                }
                msg.up().up().up().c('ext-info', { xmlns: "chat:xmpp:extend" }).c('type').t('image');
            }

            MiniIM.getConnection().send(msg);
        }

        return true;
    };

    self.loadArchive = function(name, id, type, timepoint, count) {
        var params = { xmlns: Strophe.NS.ARCHIVE };
        switch (type) {
            case MiniIM.TYPE.ROOM:
                params['with'] = name;
                params['contact'] = name + '@groupchat';
                break;
            case MiniIM.TYPE.PRIVATE:
                params['contact'] = id ? (id + "@chat") : "";
                params['with'] = name;
                //params['with'] = id;
                //params['name'] = name;
        }
        if (timepoint != undefined) {
            params['timepoint'] = timepoint;
        }
        if (count != undefined) {
            params['count'] = count;
        }
        MiniIM.getConnection().send(StropheLib.$iq({ type: 'get', from: MiniIM.getOwnJid() }).c('history', params));

    };

    self.loadRecentContacts = function(from, offset) {
        MiniIM.getConnection().send(StropheLib.$iq({ type: 'get', from: MiniIM.getOwnJid() })
            .c('contact', { xmlns: Strophe.NS.ARCHIVE, 'recent': '1', 'from': from, 'count': offset }));
    }

    self.loadOnlineUserList = function() {
        MiniIM.getConnection().send(StropheLib.$iq({ type: 'get', from: MiniIM.getOwnJid() })
            .c('online-user', { xmlns: Strophe.NS.ARCHIVE }));
    }

    self.loadSiteOnlineUserList = function() {
        MiniIM.getConnection().send(StropheLib.$iq({ type: 'get', from: MiniIM.getOwnJid() })
            .c('online-user', { xmlns: Strophe.NS.ARCHIVE, 'site': '1' }));
    }

    self.sendChatInvitation = function(user) {
        MiniIM.getConnection().send(StropheLib.$iq({
            type: 'get',
            from: MiniIM.getOwnJid(),
            to: (user + '@' + Strophe.getDomainFromJid(MiniIM.getOwnJid()))
        }).c('invite', { xmlns: Strophe.NS.ARCHIVE }));
    }

    self.removeArchive = function(name) {
        MiniIM.getConnection().send(StropheLib.$iq({ type: 'get', from: MiniIM.getOwnJid() })
            .c('history', { xmlns: Strophe.NS.ARCHIVE, 'with': name, 'clear': 1 }));
    }

    self.removeRoomMessage = function(domain, messageId) {
        MiniIM.getConnection().send(StropheLib.$iq({ type: 'get', from: MiniIM.getOwnJid() })
            .c('delete', { xmlns: Strophe.NS.ARCHIVE, 'messageid': messageId, 'roomjid': MiniIM.Util.toConferenceJid(domain) }));
    }

    self.markMessageReaded = function(messageId) {
        MiniIM.getConnection().send(StropheLib.$iq({ type: 'get', from: MiniIM.getOwnJid() })
            .c('unread', { xmlns: Strophe.NS.ARCHIVE, 'messageid': messageId }));
    };

    self.markAllMessagesRead = function(name) {
        MiniIM.getConnection().send(StropheLib.$iq({ type: 'get', from: MiniIM.getOwnJid() })
            .c('unread', { xmlns: Strophe.NS.ARCHIVE, 'with': MiniIM.Util.toJid(name) }));
    }

    self.loadUnreadMessages = function() {
        MiniIM.getConnection().send(StropheLib.$iq({ type: 'get', from: MiniIM.getOwnJid() })
            .c('unread', { xmlns: Strophe.NS.ARCHIVE, 'list': '1' }));
    };

    self.registerSessionId = function(sessionId) {
        MiniIM.getConnection().send(StropheLib.$iq({ type: 'get', from: MiniIM.getOwnJid() })
            .c('query', { xmlns: Strophe.NS.PRIVATE }).c('properties', { xmlns: 'chat:user:properties', 'sessionid': sessionId }).tree());
    };

    self.setStatus = function(roomName, status) {
        var ownerJid = MiniIM.getOwnJid();
        var roomJid = roomName + '@conference.' + Strophe.getDomainFromJid(ownerJid);
        MiniIM.getConnection().send(StropheLib.$pres({ from: ownerJid, to: roomJid }).c('status').t(status));
    };

    self.serverTime = function() {
        MiniIM.getConnection().send(StropheLib.$iq({ type: 'get', from: MiniIM.getOwnJid() }).c('time', { xmlns: Strophe.NS.TIME }).tree());
    };

    self.updateProfile = function(sessionId) {
        MiniIM.getConnection().send(StropheLib.$iq({ type: 'set', from: MiniIM.getOwnJid() }).c('update', { xmlns: Strophe.NS.ARCHIVE, 'sessionid': sessionId }));
    };

    self.savePreference = function(name, value) {
        MiniIM.Util.sendIQPrivate(false, name, _xmlns_preference_prefix + name, { 'value': value });
    }

    self.loadPreference = function(name) {
        MiniIM.Util.sendIQPrivate(true, name, _xmlns_preference_prefix + name);
    }

    return self;

}(MiniIM.Action || {}, StropheLib.Strophe));


MiniIM.Handler = (function(self, Strophe) {

    var _registeredHandlers = {};

    self.KEYS = {
        CONNECTED: 1, // for connection is ok
        PRESENCE: 2, // for chat room presence event
        MESSAGE: 3, // for message event
        ARCHIVE: 4, // for archive loading event
        ERROR: 5, // for error message handler
        RECENT_CONTACTS: 6, // for getting recent contacts
        UNREAD: 7, // for unread messages
        ONLINE_USERS: 8, // for online user list
        TIME: 9, // for time sync
        FONT_SETTINGS: 10, // for font settings
        USER_STATUS: 11, // for user(in room) status changed.
        MESSAGE_DELETED: 12, // for message deleted event
        PREFERENCE: 13, // for preference event
        CHAT_INVITE: 14, // for chat invite event
        AUTO_RECONNECT: 15, // for auto-reconnect event
        PRESENCE_BC: 16, // for broadcast presnce event
        SITE_ONLINE_USERS: 17 // for site online user list event

    };

    self.addHandler = function(key, handler) {
        if (_registeredHandlers[key] === undefined) {
            _registeredHandlers[key] = [];
        }
        _registeredHandlers[key].push(handler);
    };

    self.removeHandler = function(key, handler) {
        var handlers = _registeredHandlers[key];
        if (handlers != undefined) {
            for (let i in handlers) {
                if (handler == arr[i]) {
                    handlers.splice(i, 1);
                }
            }
        }
        _registeredHandlers[key] = handlers;
    };

    self.reset = function() {
        _registeredHandlers = {};
    }

    self.notifyHandlers = function(key, arg) {
        var handlers = _registeredHandlers[key],
            i;
        if (handlers != undefined) {
            for (let i in handlers) {
                handlers[i].proccess(self, arg);
            }
        }
    };

    self.Strophe = {
        /*
         Status: {
                ERROR: 0,
                CONNECTING: 1,
                CONNFAIL: 2,
                AUTHENTICATING: 3,
                AUTHFAIL: 4,
                CONNECTED: 5,
                DISCONNECTED: 6,
                DISCONNECTING: 7,
                ATTACHED: 8,
                REDIRECT: 9,
                CONNTIMEOUT: 10
            },
        */

        Connect: function(status, condition) {
            switch (status) {
                case Strophe.Status.CONNECTED:
                    MiniIM.log('[Connection] Connected');
                    MiniIM.getConnection().send(StropheLib.$pres().c('priority').t('1'));
                    if (MiniIM.getSessionId() != null) {
                        MiniIM.Action.registerSessionId(MiniIM.getSessionId());
                    }
                    if (_registeredHandlers[self.KEYS.UNREAD] == undefined) {
                        self.notifyHandlers(self.KEYS.CONNECTED, { code: status, condition: condition ? condition : 'Connected' });
                    }
                    break;
                case Strophe.Status.ATTACHED:
                    MiniIM.log('[Connection] Attached');
                    break;
                case Strophe.Status.DISCONNECTED:
                    MiniIM.log('[Connection] Disconnected');
                    MiniIM.Event.onDisconnect();
                    //self.notifyHandlers(self.KEYS.ERROR, { code: status, condition: condition ? condition : 'Disconnected' });
                    break;
                case Strophe.Status.AUTHFAIL:
                    MiniIM.log('[Connection] Authentication failed');
                    self.notifyHandlers(self.KEYS.ERROR, { code: status, condition: condition ? condition : 'Authentication failed' });
                    break;
                case Strophe.Status.CONNECTING:
                    MiniIM.log('[Connection] Connecting');
                    break;
                case Strophe.Status.DISCONNECTING:
                    MiniIM.log('[Connection] Disconnecting');
                    break;
                case Strophe.Status.AUTHENTICATING:
                    MiniIM.log('[Connection] Authenticating');
                    break;
                case Strophe.Status.ERROR:
                    MiniIM.log('[Connection] ERROR');
                    self.notifyHandlers(self.KEYS.ERROR, { code: status, condition: condition ? condition : 'Error' });
                    break;
                case Strophe.Status.CONNFAIL:
                    MiniIM.log('[Connection] CONNFAIL');
                    self.notifyHandlers(self.KEYS.ERROR, { code: status, condition: condition ? condition : 'CONNFAIL' });
                    break;
                default:
                    MiniIM.log('[Connection] Unkown');
            }
        }
    };

    self.Jabber = {
        Presence: function(msg) {
            MiniIM.log('[Jabber] Presence');
            try {

                var jsonIQ = xmlToJSON.parseXML(msg);
                //console.log(msg, jsonIQ);

                //status
                if (jsonIQ['status']) {
                    var status = jsonIQ['status'][0]._text,
                        fromUser = MiniIM.Util.getRealName(jsonIQ['_attr']['from']._value);
                    self.notifyHandlers(self.KEYS.USER_STATUS, { 'fromUser': fromUser, 'status': status });
                }

                //leave or join
                if (jsonIQ['x'] && jsonIQ['extend']) {
                    if (jsonIQ['x'][0]._ns.indexOf(Strophe.NS.MUC) > -1 && jsonIQ['_attr']['type']) {
                        var presenceType = jsonIQ['_attr']['type']._value;
                        if (presenceType !== 'error') {
                            self.notifyHandlers(self.KEYS.PRESENCE, {
                                'fromJid': jsonIQ['_attr']['from']._value,
                                'usr_id': jsonIQ['extend'][0]['id'][0]._text.toString(),
                                'type': presenceType === 'unavailable' ? 'leave' : 'join'
                            });
                        }
                    }
                }

            } catch (ex) {
                MiniIM.log('Exception on MiniIM.Handler.Jabber.Presence: ' + ex.message);
                MiniIM.log(ex.stack);
            }
            return true;
        },

        Message: function(msg) {
            MiniIM.log('[Jabber] Message');
            //console.log(msg);
            try {
                var message, messageRecord = {},
                    jsonIQ = xmlToJSON.parseXML(msg),
                    fromJid = jsonIQ['_attr']['from']._value,
                    type = jsonIQ['_attr']['type']._value;

                //console.log(msg, jsonIQ);
                if (jsonIQ['sent']) {
                    if (jsonIQ['sent'][0]['forwarded']) {
                        message = jsonIQ['sent'][0]['forwarded'][0]['message'][0];
                        messageRecord.receiver = MiniIM.Util.getRealName(message['_attr']['to']._value);
                        messageRecord.receiverId = message['receiverid'][0]._text;
                        messageRecord.forwarded = true;
                    }
                } else {
                    message = jsonIQ;
                }

                if (fromJid !== Strophe.getDomainFromJid(fromJid)) {
                    if (type == 'error') {
                        self.notifyHandlers(self.KEYS.ERROR, {
                            'fromJid': fromJid,
                            'id': message['_attr']['flag']._value,
                            'code': message['error']['0']['_attr']['code']._value,
                            'message': message['error']['0']._text
                        });
                    } else if ((type == 'groupchat' || type == 'chat') && message['body']) {
                        var sender = MiniIM.Util.getRealName(fromJid),
                            body = message['body'][0]._text,
                            messageId = message['messageid'][0]._text,
                            senderId = (type === 'groupchat') ? message['profileId'][0]._text : message['senderid'][0]._text,
                            timestamp = message['timestamp'][0]._text;
                        if (message['delay']) {
                            if (type === 'groupchat') {
                                return true;
                            }
                            timestamp = message['delay'][0]['_attr']['stamp']._value;
                        }
                        messageRecord.fromJid = fromJid;
                        messageRecord.sender = sender;
                        messageRecord.type = type;
                        messageRecord.message = body;
                        messageRecord.senderId = senderId.toString();
                        messageRecord.id = messageId.toString();
                        messageRecord.time = timestamp || new Date().toGMTString();
                        if (message['ext-info']) {
                            var extInfo = message['ext-info'][0];
                            messageRecord['sysType'] = extInfo.type[0]._text;
                            messageRecord['sysMsgId'] = extInfo['msgid'] ? extInfo['msgid'][0]._text : '';
                        }
                        if (message['x']) {
                            if (message['x'][0]['image']) {
                                var imageInfo = message['x'][0]['image'][0];
                                messageRecord['sysType'] = 'image';
                                messageRecord['sysLink'] = imageInfo['link'][0]._text;
                                if (imageInfo['ix']) {
                                    messageRecord['ix'] = imageInfo['ix'][0]._text;
                                }
                                if (imageInfo['iy']) {
                                    messageRecord['iy'] = imageInfo['iy'][0]._text;
                                }
                                if (imageInfo['lifetime']) {
                                    messageRecord['lifetime'] = imageInfo['lifetime'][0]._text;
                                }
                            }
                        }
                        if (message['invite']) {
                            messageRecord['sysType'] = 'invite_message';
                        }
                        self.notifyHandlers(self.KEYS.MESSAGE, messageRecord);
                    }
                }
            } catch (ex) {
                MiniIM.log('Exception on MiniIM.Handler.Jabber.Message: ' + ex.message);
                MiniIM.log(ex.stack);
            }
            return true;
        },

        Archive: function(iq) {
            MiniIM.log('[Jabber] Archive');
            try {

                var jsonIQ = xmlToJSON.parseXML(iq);
                // console.log(iq, jsonIQ);

                //unread
                if (jsonIQ['unread']) {
                    if (jsonIQ['unread'][0]['_attr']['list'] != undefined) {
                        MiniIM.log('[Jabber] Unread messages');
                        var unreadMap = {},
                            messages = jsonIQ['unread'][0]['message'] || [];
                        for (var i in messages) {
                            var msg = MiniIM.Util.parseMessage(messages[i]);
                            if (unreadMap[msg.senderId] == undefined) {
                                unreadMap[msg.senderId] = [];
                            }
                            unreadMap[msg.senderId].push(msg);
                        }
                        self.notifyHandlers(self.KEYS.UNREAD, { 'count': messages.length, 'messages': unreadMap });
                    }
                    //history
                } else if (jsonIQ['history']) {
                    MiniIM.log('[Jabber] History');
                    if (jsonIQ['history'][0]['error']) {
                        self.notifyHandlers(self.KEYS.ERROR, { code: 5001, condition: condition ? condition : 'history load failed' });
                        return;
                    }
                    var messages = jsonIQ['history'][0]['message'] || [],
                        timepoint = null,
                        newArr = [],
                        withJid = jsonIQ['history'][0]['_attr']['with']._value;

                    for (var i in messages) {
                        var msg = MiniIM.Util.parseMessage(messages[i]);
                        newArr.push(msg);
                    }

                    if (messages.length > 0) {
                        timepoint = messages[0]['time'][0]._text;
                    }
                    self.notifyHandlers(self.KEYS.ARCHIVE, { 'jid': withJid, 'timepoint': timepoint, 'count': newArr.length, 'messages': newArr });
                    //contact
                } else if (jsonIQ['contact'] && jsonIQ['contact'][0]['_attr']['recent'] != undefined) {
                    MiniIM.log('[Jabber] Receive recent contacts');
                    var contactMap = {},
                        contacts = jsonIQ['contact'][0]['contactitem'] || [];
                    for (var i in contacts) {
                        var msg = MiniIM.Util.parseMessage(contacts[i]['message'][0]);
                        msg['contactId'] = contacts[i]['id'][0]._text.toString();
                        msg['contactName'] = contacts[i]['name'][0]._text;
                        contactMap[msg['contactId']] = msg;
                    }
                    self.notifyHandlers(self.KEYS.RECENT_CONTACTS, { 'contacts': contactMap });
                    //online-user
                } else if (jsonIQ['online-user']) {
                    var users = [];
                    if (jsonIQ['online-user'][0]._text) {
                        users = jsonIQ['online-user'][0]._text.split(',')
                    }
                    MiniIM.log('[Jabber] Receive chat room online user list');
                    self.notifyHandlers(self.KEYS.ONLINE_USERS, { 'room': MiniIM.getDomain(), 'list': users });
                    //invite
                } else if (jsonIQ['invite']) {
                    var fromStr = jsonIQ['invite'][0]['_attr']['from']._value;
                    self.notifyHandlers(self.KEYS.CHAT_INVITE, { sender: Strophe.getNodeFromJid(fromStr) });
                }

            } catch (ex) {
                MiniIM.log('Exception on MiniIM.Handler.Jabber.Archive: ' + ex.message);
                MiniIM.log(ex.stack);
            }

            return true;
        },

        Bookmarks: function(iq) {
            MiniIM.log('[Jabber] Bookmarks');
            try {
                var jsonIQ = xmlToJSON.parseXML(iq);
                //console.log(iq, jsonIQ);
                if (jsonIQ['query']) {
                    var nodeObj = jsonIQ['query'][0]['online_status'];
                    if (nodeObj) {
                        if (nodeObj[0]['value']) {
                            var data = {};
                            data.online_status = nodeObj[0]['value'][0]._text;
                            self.notifyHandlers(self.KEYS.PREFERENCE, data);
                        }
                    }
                }
            } catch (ex) {
                MiniIM.log('Exception on MiniIM.Handler.Jabber.Bookmarks: ' + ex.message);
                MiniIM.log(ex.stack);
            }
            return true;
        }

    };

    return self;

}(MiniIM.Handler || {}, StropheLib.Strophe));


MiniIM.Event = (function(self, Strophe) {

    self.onDisconnect = function() {
        if (_disconnected) {
            return true;
        }
        MiniIM.log('Disconnect event received, try reconnect if need');
        if (MiniIM.getService().indexOf("ws") == 0 || MiniIM.getService().indexOf("wss") == 0) {
            if (_retry_times <= MAX_RETRY_TIMES) {
                MiniIM.log('Websocket connection is disconnected, will reconnect at #' + (_retry_times++) + ' times');
                setTimeout(function() {
                    MiniIM.connect(MiniIM.getLoginName(), MiniIM.getLoginPassword());
                }, 3000);
            } else {
                _retry_times = 1;
                MiniIM.log('Can not create Websocket connection!');
                MiniIM.Handler.notifyHandlers(MiniIM.Handler.KEYS.ERROR, {
                    code: Strophe.Status.DISCONNECTED,
                    condition: 'Reconnect failed'
                });
                MiniIM.disconnect();
            }
        } else {
            MiniIM.disconnect();
        }
        return true;
    };

    return self;

}(MiniIM.Event || {}, StropheLib.Strophe));


MiniIM.Util = (function(self, Strophe) {

    self.getRealName = function(jid) {
        var realName = '';

        if (jid.indexOf('@conference.') > 0 && jid.indexOf('/') > 0) {
            // For conference jid, get resource part of jid
            realName = self.removeDomainFromUsername(Strophe.getResourceFromJid(jid));
        } else {
            // For normal jid, get node part of jid
            realName = self.removeDomainFromUsername(Strophe.getNodeFromJid(jid));
        }
        return realName;
    };

    self.toJid = function(username) {
        return username.toLowerCase() + NAME_SEPARATOR + MiniIM.getDomain() + '@' + Strophe.getDomainFromJid(MiniIM.getOwnJid());
    };

    self.toConferenceJid = function(roomName) {
        return roomName + '@conference.' + Strophe.getDomainFromJid(MiniIM.getOwnJid());
    };

    self.sendIQPrivate = function(isGet, name, xmlns, data) {
        if (isGet) {
            MiniIM.getConnection().send(StropheLib.$iq({ type: 'get', from: MiniIM.getOwnJid() })
                .c('query', { 'xmlns': Strophe.NS.PRIVATE }).c(name, { 'xmlns': xmlns }).tree());
        } else {
            var iq = StropheLib.$iq({ type: 'set', from: MiniIM.getOwnJid(), id: 'edit1' })
                .c('query', { 'xmlns': Strophe.NS.PRIVATE }).c(name, { 'xmlns': xmlns });

            for (var item in data) {
                iq.c(item).t(data[item] + '').up();
            }

            MiniIM.getConnection().send(iq.tree());
        }

    }

    self.removeDomainFromUsername = function(username) {
        if (username) {
            var separatorIdx = username.lastIndexOf(NAME_SEPARATOR + MiniIM.getDomain());
            if (separatorIdx > 0) {
                return username.substring(0, separatorIdx);
            }
        }
        return username;
    };

    self.parseMessage = function(messageJSON) {
        if (!messageJSON.senderid) {
            console.log('message xml error,not find senderid:', messageJSON);
            return {};
        }

        var sender = messageJSON.sender ? messageJSON.sender[0]._text : '',
            senderId = messageJSON.senderid[0]._text.toString(),
            receiverId = messageJSON.receiverid ? messageJSON.receiverid[0]._text.toString() : '',
            id = messageJSON.id[0]._text.toString(),
            message = messageJSON.body[0]._text,
            time = messageJSON.time[0]._text;

        var messageRecord = {
            'id': id,
            'sender': sender,
            'senderId': senderId,
            'message': message,
            'receiverId': receiverId,
            'time': time
        };
        if (messageJSON['ext-info']) {
            var extInfo = messageJSON['ext-info'][0];
            messageRecord['sysType'] = extInfo.type[0]._text;
            messageRecord['sysMsgId'] = extInfo['msgid'] ? extInfo['msgid'][0]._text : '';
        }

        if (messageJSON['x']) {
            if (messageJSON['x'][0]['image']) {
                var imageInfo = messageJSON['x'][0]['image'][0];
                messageRecord['sysType'] = 'image';
                messageRecord['sysLink'] = imageInfo['link'][0]._text;

                if (imageInfo['ix']) {
                    messageRecord['ix'] = imageInfo['ix'][0]._text;
                }

                if (imageInfo['iy']) {
                    messageRecord['iy'] = imageInfo['iy'][0]._text;
                }

                if (imageInfo['lifetime']) {
                    messageRecord['lifetime'] = imageInfo['lifetime'][0]._text;
                }

            }
        }

        if (messageJSON['invite']) {
            messageRecord['sysType'] = 'invite_message';
        }

        return messageRecord;
    }

    return self;

}(MiniIM.Util || {}, StropheLib.Strophe));



export default MiniIM;
